package com.onion.utils.data;

import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.*;

public class DataConverter {

    private Logger logger = LoggerFactory.getLogger(DataConverter.class);

    private Map<Class<? extends java.io.Serializable>, GenericDataConverter<?>> dataConverterMap = new HashMap<>();
    private volatile static DataConverter dataConverter;
    private volatile static Object LOCK = new Object();

    private DataConverter(){}

    public static DataConverter getDataConverter(){
        if(dataConverter == null){
            synchronized (LOCK){
                if(dataConverter == null){
                    DataConverter converter = new DataConverter();
                    converter.initConverter();
                    dataConverter = converter;
                }
            }
        }
        return dataConverter;
    }

    private void initConverter(){
        ServiceLoader<GenericDataConverter> serviceLoader= ServiceLoader.load(GenericDataConverter.class);
        Iterator<GenericDataConverter> itor = serviceLoader.iterator();
        Set<String> convertTypes = new HashSet<>();
        while(itor.hasNext()){
            GenericDataConverter dataConverter = itor.next();
            convertTypes.add(dataConverter.getType().getSimpleName());
        }
        logger.info("[onion]默认数据转换器加载完成：size={}, types={}", dataConverterMap.size(), JSON.toJSONString(convertTypes));
    }

    private <T extends java.io.Serializable> void addConverter(GenericDataConverter<T> genericConverter){
        synchronized (dataConverterMap){
            GenericDataConverter srcConverter = dataConverterMap.get(genericConverter.getType());
            dataConverterMap.put(genericConverter.getType(), genericConverter);
            if(srcConverter != null){
                logger.warn("[onion]默认数据转换器覆盖替换:type={}, {}->{}", srcConverter.getType(), srcConverter.getClass().getName(),
                            genericConverter.getClass().getName());
            }
        }
    }

    /**
     * 注册自定义数据转换器
     * @param customerConverter
     * @param <T>
     */
    public static <T extends java.io.Serializable> void registerConverter(GenericDataConverter<T> customerConverter){
        getDataConverter().addConverter(customerConverter);
    }

    /**
     * 获取数据转换器
     * @return
     */
    private static Map<Class<? extends java.io.Serializable>, GenericDataConverter<?>> getConverterMap(){
        return getDataConverter().dataConverterMap;
    }

    public static GenericDataConverter<?> getConverter(Class<?> clazz){
        return getConverterMap().get(clazz);
    }

    /**
     * 字节数组转换字符串
     * @param bytes
     * @return
     */
    public static String bytes2String(byte[] bytes){
        return bytes2String(bytes, "UTF-8");
    }

    /**
     * 字节数组转换字符串
     * @param bytes
     * @param charset
     * @return
     */
    public static String bytes2String(byte[] bytes, String charset){
        try {
            return new String(bytes, charset);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("数据转换异常！", e);
        }
    }

    /**
     * 数据转换[数组转对象]
     * @param bytes
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T extends java.io.Serializable> T convert(byte[] bytes, Class<T> clazz){
        return convert(bytes, clazz, "UTF-8");
    }

    /**
     * 数据转换[数组转对象]
     * @param bytes
     * @param clazz
     * @param charset
     * @param <T>
     * @return
     */
    public static <T extends java.io.Serializable> T convert(byte[] bytes, Class<T> clazz, String charset){
        GenericDataConverter<? extends Serializable> dataConverter = getConverter(clazz);
        if(dataConverter == null){
            return (T)dataConverter.convert(bytes, charset);
        }else if(clazz == String.class){
            return (T)bytes2String(bytes, charset);
        }else {
            throw new RuntimeException("不支持的数据类型:" + clazz.getName());
        }
    }

    /**
     * 数据转换[字符串转对象]
     * @param data
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T extends java.io.Serializable> T convert(String data, Class<T> clazz){
        GenericDataConverter<? extends Serializable> dataConverter = getConverterMap().get(clazz);
        if(dataConverter == null){
            return (T)dataConverter.convert(data);
        }else if(clazz == String.class){
            return (T)data;
        }else {
            throw new RuntimeException("不支持的数据类型:" + clazz.getName());
        }
    }

}